/*
 *  Copyright 2008 The MITRE Corporation (http://www.mitre.org/). All Rights Reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.mitre.mrald.util;

import org.mitre.mrald.util.Config;
import org.mitre.mrald.util.Mailer;
import org.mitre.mrald.util.MiscUtils;
import java.io.FileInputStream;
import java.io.InputStream;
import java.io.IOException;
import java.util.*;

import org.mitre.mrald.parser.ParserElement;
import org.mitre.mrald.query.BroadcastQueryTarget;
import org.mitre.mrald.query.BroadcastQueryTargetsParser;
import org.mitre.mrald.query.BroadcastTargetProvider;
import org.mitre.mrald.query.LinkElement;
import org.mitre.mrald.query.SqlElements;
import org.xml.sax.helpers.XMLReaderFactory;
import org.xml.sax.InputSource;
import org.xml.sax.XMLReader;
/**
 * A SimpleTargetProvider provides a list of other MRALD instances that can answer
 * a query built by the components supplied in the {@link #getTargets getTargets} method.
 * This implementation of BroadcastTargetProvider works off a manually defined xml file
 * and declares a target to be OK if it is mapped to the current datasource in
 * that xml file.
 *
 * @author Jeffrey Hoyt
  */
public class SimpleTargetProvider implements BroadcastTargetProvider
{
    private List<BroadcastQueryTarget> allTargets;
    public static final String TARGETS_FILE = "broadcastTargets.xml";
    private String xmlFileLoc = Config.getFinalPropertiesLocation() + TARGETS_FILE;


    public SimpleTargetProvider()
    {
        reload();
    }

    public SimpleTargetProvider(boolean loadXmlfile)
    {
        if( loadXmlfile )
        {
            reload();
        }
    }

    /**
     *  checks to see if there is a target for the supplied datasource
     *
     * @param sqlElements List of SqlElements that are parts of a single query
     * @param linkElements List of LinkElements that define the joins between tables
     *  This could just as easily be part of the List above, but they are already
     *  separated out, and special handling may be required for these.
     * @param datasource The local datasource name, so we know which local schema
     *   the query is built against
     *
     * @return A List of appropriate BroadcastQueryTargets which for the query
     * (where "the query" is the one which would result from composing a query
     * from the component parts)
     */
    public List<BroadcastQueryTarget> getTargets( List<ParserElement> sqlElements, List <LinkElement> linkElements, String datasource )
    {
        List<BroadcastQueryTarget> targets = new ArrayList<BroadcastQueryTarget>();
        for( BroadcastQueryTarget potentialTarget : allTargets )
        {
            if( potentialTarget.getLocalDatasource().equals( datasource ) )
            {
                LinkElement[] links = new LinkElement[linkElements.size()];
                for(int i = 0; i < linkElements.size(); i++)
                {
                    links[i] = linkElements.get(i);
                }
                SqlElements[] parts = new SqlElements[sqlElements.size()];
                for(int i = 0; i < sqlElements.size(); i++)
                {
                    parts[i] = (SqlElements) sqlElements.get(i);
                }
                potentialTarget.setLinkElements(links);
                potentialTarget.setSqlElements(parts);
                targets.add( potentialTarget );
                // MraldOutFile.appendToFile( "adding " + potentialTarget.toString() );
            }
            // else MraldOutFile.appendToFile( "not adding " + potentialTarget.toString() );

        }
        return targets;
    }

    /**
     * Reloads the list of potential targets from source
     */
    public void reload(  )
    {
        //create input stream to xml source document
        InputStream in = null;
        try
        {
            in = new FileInputStream( xmlFileLoc );
        }
        catch ( IOException e )
        {
            String mailText = MiscUtils.formatThrowable( e );
            System.out.println(mailText);
            Mailer.send( Config.getProperty( "MAILTO" ),
                 "SimpleTargetProvider",
                 Config.getProperty( "SMTPHOST" ),
                 mailText, "Error loading targets in SimpleTargetProvider" );
        }
        reload(in);
    }

    /**
     *  This does the real work.
     */
    public void reload( InputStream in )
    {
        try
        {
            // Create SAX 2 parser...
            XMLReader xr = XMLReaderFactory.createXMLReader();
            // Set the ContentHandler...
            BroadcastQueryTargetsParser parser = new BroadcastQueryTargetsParser();
            xr.setContentHandler(parser);
            // Parse the file...
            xr.parse(new InputSource(in));
            in.close();
            allTargets = parser.getBroadcastQueryTargets();
        }
        catch ( Exception e )
        {
            String mailText = MiscUtils.formatThrowable( e );
            e.printStackTrace();
            Mailer.send( Config.getProperty( "MAILTO" ),
                         "SimpleTargetProvider",
                         Config.getProperty( "SMTPHOST" ),
                         mailText, "Error loading targets in SimpleTargetProvider" );
        }
    }
}

